package com.mt.restaurant.service.staff.impl;

import com.mt.common.core.utils.ConfigManager;
import com.mt.common.system.entity.Config;
import com.mt.common.system.service.ConfigService;
import com.mt.restaurant.dao.staff.RoleSalaryDao;
import com.mt.restaurant.dao.staff.SalarySettlementDao;

import com.mt.common.core.exception.BusinessException;
import com.mt.common.core.web.base.PageDTO;
import com.mt.common.core.web.base.PageResultDTO;
import com.mt.common.core.web.base.BaseEntity;
import com.mt.common.core.web.BaseService;
import com.mt.restaurant.dao.staff.StaffAttendanceRecordsDao;
import com.mt.restaurant.entity.material.Cost;
import com.mt.restaurant.entity.staff.RoleSalary;
import com.mt.restaurant.entity.staff.StaffAttendanceRecords;
import com.mt.restaurant.service.material.CostService;
import com.mt.restaurant.service.staff.StaffAttendanceRecordsService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.mt.restaurant.entity.staff.SalarySettlement;
import com.mt.restaurant.service.staff.SalarySettlementService;
import org.beetl.ext.fn.DateFunction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Transactional
public class SalarySettlementServiceBean extends BaseService implements SalarySettlementService {

    private static Logger logger = LogManager.getLogger();

	@Autowired
	private SalarySettlementDao salarySettlementDao;

	@Resource
	private RedisTemplate<String, List<SalarySettlement>> redisTemplate;

	@Autowired
	StringRedisTemplate stringRedisTemplate;


	@Autowired
	private CostService costService;
	/**
	 * 根据分页参数查询工资结算集合
	 *
	 * @param pageDTO 分页条件
	 */
	@Override
	public PageResultDTO findSalarySettlements(PageDTO pageDTO){
        pageDTO.setStartIndex((pageDTO.getCurrentPage()-1)*pageDTO.getPageSize());
		//TODO:请在此校验参数的合法性
		this.validateFindSalarySettlements(pageDTO);
		List<SalarySettlement> salarySettlementDTOS = this.salarySettlementDao.findSalarySettlements(pageDTO);
		Long totalCount = this.salarySettlementDao.findSalarySettlementTotalCount(pageDTO);

		PageResultDTO pageResultDTO = new PageResultDTO();
		pageResultDTO.setTotalCount(totalCount);
		pageResultDTO.setDatas(salarySettlementDTOS);

		return pageResultDTO;
	}

	/**
	 * 查询全部工资结算集合
	 *
	 */
	@Override
	public List<SalarySettlement> findAllSalarySettlements(){
		return this.salarySettlementDao.findAllSalarySettlements();
	}

	/**
	 * 查询所有工资结算集合(只提取ID 和 Name)
	 *
	 */
	@Override
	public List<SalarySettlement> findAllSalarySettlementsWithIdName(){
		//TODO:请在此校验参数的合法性
		this.validateFindAllSalarySettlementsWithIdName();
		return this.salarySettlementDao.findAllSalarySettlementsWithIdName();
	}

	/**
	 * 根据名称查询工资结算集合(只提取ID 和 Name)
	 *
	 * @param salarySettlementName 名称
	 */
	@Override
	public List<SalarySettlement> findSalarySettlementsWithIdNameByName(String salarySettlementName){
		//TODO:请在此校验参数的合法性
		this.validateFindSalarySettlementsWithIdNameByName(salarySettlementName);
		//TODO:缓存取对应参数
		Set<String> keys = stringRedisTemplate.keys("searchData:SalarySettlement_where_salarySettlementName_" + salarySettlementName);
		List<SalarySettlement> salarySettlements = new ArrayList<>();
		if (keys.isEmpty()) {
		salarySettlements = this.salarySettlementDao.findSalarySettlementsWithIdNameByName(salarySettlementName);
		redisTemplate.opsForValue().set("searchData:SalarySettlement_where_salarySettlementName_" + salarySettlementName, salarySettlements, 30, TimeUnit.DAYS);
		} else {
		salarySettlements = redisTemplate.opsForValue().get("searchData:SalarySettlement_where_salarySettlementName_" + salarySettlementName);
		}
		return salarySettlements;
	}

	/**
	 * 根据ID查询指定的工资结算(只提取ID 和 Name)
	 *
	 * @param salarySettlementId Id
	 */
	@Override
	public SalarySettlement findSalarySettlementsWithIdNameById(Long salarySettlementId){
		//TODO:请在此校验参数的合法性
		this.validateFindSalarySettlementsWithIdNameById(salarySettlementId);
		return this.salarySettlementDao.findSalarySettlementsWithIdNameById(salarySettlementId);
	}

	/**
	 * 根据ID查询指定的工资结算
	 *
	 * @param salarySettlementId Id
	 */
	@Override
	public SalarySettlement findSalarySettlement(Long salarySettlementId){
		//TODO:请在此校验参数的合法性
		this.validateFindSalarySettlement(salarySettlementId);
		return this.salarySettlementDao.findSalarySettlement(salarySettlementId);
	}

	/**
	 * 根据ID查询指定的工资结算(包含外键)
	 *
	 * @param salarySettlementId Id
	 */
	@Override
	public SalarySettlement findSalarySettlementWithForeignName(Long salarySettlementId){
		//TODO:请在此校验参数的合法性
		this.validateFindSalarySettlementWithForeignName(salarySettlementId);
		return this.salarySettlementDao.findSalarySettlementWithForeignName(salarySettlementId);
	}

	/**
	 * 新增工资结算
	 *
	 * @param salarySettlement 实体对象
	 */
	@Override
	public SalarySettlement saveSalarySettlement(SalarySettlement salarySettlement){
		//TODO:请在此校验参数的合法性
		this.validateSaveSalarySettlement(salarySettlement);
		//TODO:填充公共参数
		this.setSavePulicColumns(salarySettlement);
		SalarySettlement last=this.salarySettlementDao.findSalarySettlementByStaffId(salarySettlement.getStaffId());
		if( last!=null&&last.getSettleEndDate()==null&&last.getSettleEndDate().getTime()- salarySettlement.getSettleStartDate().getTime()>0){
			throw new BusinessException("当前结算开始时间早于上次结算的最晚时间");
		}
		Long rows = this.salarySettlementDao.saveSalarySettlement(salarySettlement);
		Cost cost=new Cost();
		cost.setType("员工薪资");
		cost.setTotal((double)salarySettlement.getAmount());
		cost.setPrice((double)salarySettlement.getAmount());
		cost.setAmount(1.0);
		cost.setStatus("支出");
		this.costService.saveCost(cost);
		if(rows != 1)
		{
			String error = "新增保存工资结算出错，数据库应该返回1,但返回了 "+rows;
			throw new BusinessException(error);
		}
		return salarySettlement;
	}

	/**
	 * 更新工资结算
	 *
	 * @param salarySettlement 实体对象
	 */
	@Override
	public SalarySettlement updateSalarySettlement(SalarySettlement salarySettlement){
		//TODO:请在此校验参数的合法性
		this.validateUpdateSalarySettlement(salarySettlement);
		Long rows = this.salarySettlementDao.updateSalarySettlement(salarySettlement);
		if(rows != 1)
		{
			String error = "修改保存工资结算出错，数据库应该返回1,但返回了 "+rows+",数据可能被删除";
			throw new BusinessException(error);
		}
		return salarySettlement;
	}

	/**
	 * 根据ID删除工资结算
	 *
	 * @param salarySettlementId ID
	 */
	@Override
	public void deleteSalarySettlement(Long salarySettlementId){
		//TODO:请在此校验参数的合法性
		this.validateDeleteSalarySettlement(salarySettlementId);

		Map<Class<? extends BaseEntity>,EntityUsage> entityUsageMap = this.checkForeignEntity(SalarySettlement.class, salarySettlementId);
		if(entityUsageMap != null && entityUsageMap.size() >0){
			StringBuilder errors = new StringBuilder();
			errors.append("计划删除的数据正在被以下数引用\n");
			for(EntityUsage entityUsage : entityUsageMap.values()){
				errors.append("\t").append(entityUsage.getEntityLabel()).append("\n");
				for(Map.Entry<Long,String> entry : entityUsage.getUsageIdNames().entrySet() ){
					errors.append("\t\t").append(entry.getKey()).append("\t").append(entry.getValue()).append("\n");
				}
			}
			errors.append("，不能删除，请检查处理后再删除");
			throw  new BusinessException(errors.toString());
		}

		Long rows = this.salarySettlementDao.deleteSalarySettlement(salarySettlementId);
		if(rows != 1){
			String error = "删除工资结算出错，数据可能已经被删除";
			throw new BusinessException(error);
		}
	}
	@Autowired
	private RoleSalaryDao roleSalaryDao;

	@Autowired
	private ConfigManager configManager;

	@Autowired
	private StaffAttendanceRecordsService staffAttendanceRecordsService;
	@Override
	public int calculateSalary(Long staffId, Date startDate, Date endDate) {
		RoleSalary roleSalary=roleSalaryDao.findRoleSalaryByStaffId(staffId);
		int daySalary=0;
		if(roleSalary.getRemark()==null||roleSalary.getRemark()==""||roleSalary.getRemark().indexOf("月")!=-1){
			daySalary=roleSalary.getSalary()/30;
		}else{
			daySalary=roleSalary.getSalary();
		}
		SalarySettlement last=this.salarySettlementDao.findSalarySettlementByStaffId(staffId);
		if( last!=null&&last.getSettleEndDate()==null&&last.getSettleEndDate().getTime()- startDate.getTime()>0){
			throw new BusinessException("当前结算开始时间早于上次结算的最晚时间");
		}
		List<StaffAttendanceRecords> records=staffAttendanceRecordsService.findAllStaffAttendanceRecordsByStaffIdAndDate(staffId,startDate,endDate);
		int total=0;
		//获取当前间隔天数
		int days= (int) (Math.abs(endDate.getTime() - startDate.getTime())/(24*3600*1000))+1;
		//configManager.getConfigByName()
		total=days*daySalary;
		int times=0;
		//分组 分为缺勤 ，迟到 计算工资
		Map<String, List<StaffAttendanceRecords>> map = records.stream().collect(Collectors.groupingBy(StaffAttendanceRecords::getStatus));
		for (Map.Entry<String, List<StaffAttendanceRecords>> x:map.entrySet()){
			Config configByName = configManager.getConfigByName(x.getKey());
			int m=Integer.valueOf(configByName==null?"0":configByName.getValue());
			total-=(m*x.getValue().size());
			if("缺勤".equals(x.getKey())){
				times+=x.getValue().size();
			}
		}
		total-=times*daySalary;
		return total<0?0:total;
	}

	//TODO:---------------验证-------------------

	private void validateFindSalarySettlements(PageDTO pageDTO) {
	//TODO:请使用下面方法添加数据过滤条件
	//		pageDTO.addFilter("creatorId",this.getLoginUserId());
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateSalarySettlement()写法
	}

	private void validateFindSalarySettlementsWithIdNameByName(String salarySettlementName) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateSalarySettlement()写法
	}


	private void validateFindAllSalarySettlementsWithIdName() {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateSalarySettlement()写法
	}

	private void validateFindSalarySettlementsWithIdNameById(Long salarySettlementId) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateSalarySettlement()写法
	}

	private void validateFindSalarySettlement(Long salarySettlementId) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateSalarySettlement()写法
	}

	private void validateFindSalarySettlementWithForeignName(Long salarySettlementId) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateSalarySettlement()写法
	}

	private void validateSaveSalarySettlement(SalarySettlement salarySettlement) {
	//不为空判断
	if (salarySettlement.getEid() != null || salarySettlement.getCreatorId() != null || salarySettlement.getCreateDatetime() != null) {
	throw new BusinessException("非法请求");
	}
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateSalarySettlement()写法
	}

	private void validateUpdateSalarySettlement(SalarySettlement salarySettlement) {
	//不为空判断
	if (salarySettlement.getEid() == null) {
	throw new BusinessException("唯一标识不能为空");
	}
	//是否存在判断
	if (this.salarySettlementDao.findSalarySettlementTotalCount(PageDTO.create(SalarySettlement.FIELD_ID, salarySettlement.getEid())) == 0) {
	throw new BusinessException("修改的工资结算 " + salarySettlement.getName() + " 不存在，修改失败，请重试或联系管理员");
	}
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateSalarySettlement()写法
	}

	private void validateDeleteSalarySettlement(Long salarySettlementId) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateSalarySettlement()写法
	}

	@Override
	public boolean canDownloadAttachment(String formName, Long id) {
	return true;
	}
}
